using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SeataNet.Core.Attributes;
using SeataNet.Core.Context;
using SeataNet.Core.Exceptions;
using SeataNet.Core.Interceptors;
using SeataNet.Core.Transaction;
using System.Reflection;

namespace SeataNet.Core.AT
{
    /// <summary>
    /// AT模式事务拦截器
    ///
    /// 基于AOP（面向切面编程）的AT模式全局事务拦截器，自动管理事务的开始、提交和回滚。
    ///
    /// 职责：
    /// 1. 拦截标记[GlobalTransactional]特性的方法调用
    /// 2. 自动开启全局事务（调用IAtTransactionManager.Begin）
    /// 3. 绑定XID到当前上下文（RootContext.Bind）
    /// 4. 执行目标业务方法
    /// 5. 根据执行结果自动提交或回滚全局事务
    /// 6. 清理事务上下文（RootContext.Unbind）
    ///
    /// 工作原理（AOP拦截流程）：
    /// ```
    /// 1. 方法调用前：
    ///    - 检查方法或类是否标记[GlobalTransactional]特性
    ///    - 如果有，启动拦截逻辑
    ///    - 如果没有，直接执行方法（不拦截）
    ///
    /// 2. 开启全局事务：
    ///    - 检查当前是否已在全局事务中（RootContext.GetXid()）
    ///    - 如果是，则不开启新事务（事务传播）
    ///    - 如果否，调用Begin()开启新事务并获取XID
    ///
    /// 3. 绑定上下文：
    ///    - 调用RootContext.Bind(xid)绑定到ThreadLocal/AsyncLocal
    ///    - 确保后续代码能访问当前全局事务的XID
    ///
    /// 4. 执行业务方法：
    ///    - 调用invocation.ProceedAsync()执行目标方法
    ///    - 方法内部可能访问数据库（通过AtDataSourceProxy）
    ///    - 自动注册分支事务、写入undo_log
    ///
    /// 5. 提交或回滚：
    ///    - 成功：调用CommitAsync()提交全局事务
    ///    - 异常：调用RollbackAsync()回滚全局事务
    ///
    /// 6. 清理上下文：
    ///    - finally块中调用RootContext.Unbind()
    ///    - 确保XID不会泄漏到其他请求
    /// ```
    ///
    /// 使用场景（声明式事务）：
    /// ```csharp
    /// // 方法级别声明式事务
    /// [GlobalTransactional(TimeoutMs = 60000, Name = "business-order")]
    /// public async Task PlaceOrderAsync(Order order)
    /// {
    ///     // 1. 扣减库存（可能调用远程服务）
    ///     await _inventoryService.DeductAsync(order.ProductId, order.Quantity);
    ///
    ///     // 2. 创建订单（本地数据库）
    ///     await _orderRepository.CreateAsync(order);
    ///
    ///     // 3. 扣减余额（可能调用远程服务）
    ///     await _accountService.DeductAsync(order.UserId, order.Amount);
    ///
    ///     // 拦截器自动管理事务：
    ///     // - 成功：自动提交全局事务
    ///     // - 异常：自动回滚全局事务
    /// }
    ///
    /// // 类级别声明式事务
    /// [GlobalTransactional]
    /// public class OrderService
    /// {
    ///     // 所有public方法都自动开启全局事务
    ///     public async Task CreateOrderAsync(Order order) { ... }
    ///     public async Task CancelOrderAsync(long orderId) { ... }
    /// }
    /// ```
    ///
    /// 与Spring @Transactional的对比：
    /// - Spring：@Transactional用于本地事务（单数据库）
    /// - Seata：@GlobalTransactional用于分布式事务（多数据库/多服务）
    /// - 相同点：都使用AOP拦截器实现声明式事务
    /// - 不同点：Seata需要与TC通信，管理全局事务状态
    ///
    /// 事务传播行为：
    /// - 如果当前已在全局事务中（XID不为空），则不开启新事务
    /// - 直接执行方法，参与到现有的全局事务
    /// - 类似Spring的PROPAGATION_REQUIRED传播行为
    ///
    /// 线程安全：
    /// - 拦截器本身是线程安全的（注册为Singleton）
    /// - XID使用ThreadLocal/AsyncLocal存储，线程隔离
    /// - 每个请求有独立的全局事务上下文
    ///
    /// 注意事项：
    /// - 需要配置AOP框架（如Castle.DynamicProxy、AspectCore）
    /// - 只拦截public方法（private/protected方法不拦截）
    /// - 异常会导致回滚，需要正确处理业务异常
    /// - RootContext.Unbind()必须在finally中执行，避免XID泄漏
    /// </summary>
    public class AtTransactionInterceptor : IMethodInterceptor
    {
        private readonly IAtTransactionManager _transactionManager;
        private readonly ILogger<AtTransactionInterceptor> _logger;
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 构造函数
        ///
        /// 初始化AT模式事务拦截器，注入依赖服务。
        ///
        /// 依赖服务说明：
        /// - IAtTransactionManager：AT事务管理器，用于开启、提交、回滚全局事务
        /// - ILogger：日志记录器，用于记录事务生命周期日志
        /// - IServiceProvider：服务提供者，用于在拦截器中获取其他服务（可选）
        ///
        /// 注意事项：
        /// - 拦截器注册为Singleton生命周期
        /// - 依赖的服务也应该是线程安全的
        /// - IServiceProvider用于高级场景（如动态解析服务）
        /// </summary>
        /// <param name="transactionManager">AT事务管理器</param>
        /// <param name="logger">日志记录器</param>
        /// <param name="serviceProvider">服务提供者</param>
        public AtTransactionInterceptor(
            IAtTransactionManager transactionManager,
            ILogger<AtTransactionInterceptor> logger,
            IServiceProvider serviceProvider)
        {
            _transactionManager = transactionManager;
            _logger = logger;
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 拦截方法调用
        ///
        /// AOP框架调用此方法拦截标记[GlobalTransactional]特性的方法。
        ///
        /// 执行流程：
        /// 1. 获取方法信息（invocation.Method）
        /// 2. 检查方法级别的[GlobalTransactional]特性：
        ///    - 使用GetCustomAttributes<GlobalTransactionalAttribute>()
        ///    - 如果找到，使用该特性配置
        /// 3. 如果方法级别没有，检查类级别的特性：
        ///    - 从method.DeclaringType获取类型
        ///    - 检查类级别的[GlobalTransactional]特性
        /// 4. 如果两个级别都没有特性：
        ///    - 不拦截，直接调用invocation.ProceedAsync()执行方法
        ///    - 返回方法执行结果
        /// 5. 如果找到特性：
        ///    - 调用ExecuteInTransactionAsync()在事务中执行方法
        ///    - 传入特性配置（Timeout、Name、Retry等）
        ///
        /// 特性查找优先级：
        /// - 方法级别 > 类级别
        /// - 方法级别的特性会覆盖类级别的特性
        ///
        /// 调用时机：
        /// - AOP框架（如Castle.DynamicProxy）拦截方法时调用
        /// - 在目标方法执行前被调用
        /// - 对所有public方法都会尝试拦截
        ///
        /// 使用示例：
        /// ```csharp
        /// // 场景1：方法级别特性
        /// public class OrderService
        /// {
        ///     [GlobalTransactional(TimeoutMs = 60000)]  // 方法级别
        ///     public async Task CreateOrderAsync() { }  // 会拦截
        ///
        ///     public async Task QueryOrderAsync() { }   // 不拦截
        /// }
        ///
        /// // 场景2：类级别特性
        /// [GlobalTransactional]  // 类级别
        /// public class AccountService
        /// {
        ///     public async Task DeductAsync() { }    // 会拦截
        ///     public async Task QueryAsync() { }     // 会拦截
        /// }
        ///
        /// // 场景3：方法覆盖类
        /// [GlobalTransactional(TimeoutMs = 30000)]  // 类级别：30秒
        /// public class InventoryService
        /// {
        ///     [GlobalTransactional(TimeoutMs = 60000)]  // 方法级别：60秒（覆盖类级别）
        ///     public async Task DeductAsync() { }        // 使用60秒超时
        ///
        ///     public async Task AddAsync() { }           // 使用30秒超时（类级别）
        /// }
        /// ```
        ///
        /// 注意事项：
        /// - 只拦截public方法（AOP框架限制）
        /// - 内部方法调用不会被拦截（this.MethodA()调用MethodB()不拦截）
        /// - 反射获取特性有一定性能开销（可考虑缓存）
        /// - 未标记特性的方法直接执行，不增加额外开销
        /// </summary>
        /// <param name="invocation">方法调用上下文，包含方法信息、参数、返回值等</param>
        /// <returns>方法执行结果（可能是Task<T>或普通对象）</returns>
        public async Task<object> InterceptAsync(IMethodInvocation invocation)
        {
            var method = invocation.Method;
            var attributes = method.GetCustomAttributes<GlobalTransactionalAttribute>(true);
            
            if (!attributes.Any())
            {
                // 检查类级别的属性
                attributes = method.DeclaringType?.GetCustomAttributes<GlobalTransactionalAttribute>(true) ?? 
                           Enumerable.Empty<GlobalTransactionalAttribute>();
            }

            if (!attributes.Any())
            {
                // 没有事务注解，直接执行方法
                return await invocation.ProceedAsync();
            }

            var transactionAttribute = attributes.First();
            return await ExecuteInTransactionAsync(invocation, transactionAttribute);
        }

        /// <summary>
        /// 在全局事务中执行方法
        ///
        /// 实际执行事务拦截逻辑的核心方法，处理事务的开始、提交、回滚和上下文管理。
        ///
        /// 执行流程：
        /// 1. 检查当前是否已在全局事务中：
        ///    - 调用RootContext.GetXid()获取当前XID
        ///    - 如果XID不为空，说明已在事务中
        ///    - 直接执行方法（事务传播），不开启新事务
        /// 2. 如果不在事务中，开启新的全局事务：
        ///    - 调用_transactionManager.Begin(timeout, name)
        ///    - TC分配新的XID并返回
        ///    - 如果失败（返回null），抛出TransactionException
        /// 3. 绑定XID到当前上下文：
        ///    - 调用RootContext.Bind(xid)
        ///    - 将XID存储到ThreadLocal/AsyncLocal
        ///    - 后续代码可以通过RootContext.GetXid()获取
        /// 4. 在try块中执行业务方法：
        ///    - 调用invocation.ProceedAsync()
        ///    - 方法内部可能访问数据库、调用远程服务
        ///    - 自动注册分支事务、写入undo_log
        /// 5. 如果执行成功，提交全局事务：
        ///    - 调用_transactionManager.CommitAsync(xid)
        ///    - TC通知所有RM删除undo_log
        ///    - 返回方法执行结果
        /// 6. 如果发生异常，回滚全局事务：
        ///    - 捕获异常，记录错误日志
        ///    - 调用_transactionManager.RollbackAsync(xid)
        ///    - TC通知所有RM执行undo_log回滚
        ///    - 重新抛出原始异常（让调用方感知）
        /// 7. 在finally块中清理上下文：
        ///    - 调用RootContext.Unbind()
        ///    - 移除ThreadLocal/AsyncLocal中的XID
        ///    - 确保不会影响后续请求
        ///
        /// 事务传播示例：
        /// ```
        /// // 场景1：开启新事务
        /// [GlobalTransactional]
        /// public async Task ServiceA()  // RootContext.GetXid() == null
        /// {
        ///     // 拦截器开启新事务，获得XID=192.168.1.1:8091:2156564365
        ///     await _db.ExecuteSqlAsync(...);  // 注册分支1
        ///     await ServiceB();                 // 调用ServiceB
        ///     // 拦截器提交全局事务
        /// }
        ///
        /// // 场景2：参与现有事务（传播）
        /// [GlobalTransactional]
        /// public async Task ServiceB()  // RootContext.GetXid() == "192.168.1.1:8091:2156564365"
        /// {
        ///     // 拦截器检测到已在事务中，不开启新事务
        ///     await _db.ExecuteSqlAsync(...);  // 注册分支2（使用相同XID）
        ///     // 拦截器不提交事务（由ServiceA负责）
        /// }
        /// ```
        ///
        /// 回滚异常处理：
        /// - 如果业务方法抛出异常，自动回滚全局事务
        /// - 如果回滚也失败，记录错误日志但不抛出异常
        /// - 始终重新抛出业务方法的原始异常
        /// - 确保调用方能正确感知业务异常
        ///
        /// 调用时机：
        /// - InterceptAsync()检测到[GlobalTransactional]特性时调用
        /// - 只有需要全局事务时才调用此方法
        /// - 未标记特性的方法不会调用此方法
        ///
        /// 注意事项：
        /// - RootContext.Unbind()必须在finally中执行（避免XID泄漏）
        /// - 回滚失败不应该影响业务异常的抛出
        /// - 事务传播时不开启新事务，避免嵌套事务
        /// - 方法执行时间不能超过超时时间（默认60秒）
        /// </summary>
        /// <param name="invocation">方法调用上下文</param>
        /// <param name="attribute">[GlobalTransactional]特性配置</param>
        /// <returns>方法执行结果</returns>
        /// <exception cref="TransactionException">开启事务失败时抛出</exception>
        /// <exception cref="Exception">业务方法抛出的异常会重新抛出</exception>
        private async Task<object> ExecuteInTransactionAsync(
            IMethodInvocation invocation,
            GlobalTransactionalAttribute attribute)
        {
            var xid = RootContext.GetXid();
            var method = invocation.Method;
            var className = method.DeclaringType?.Name;
            var methodName = method.Name;

            _logger.LogDebug($"开始AT事务: Class={className}, Method={methodName}, Timeout={attribute.TimeoutMs}, Retry={attribute.Retry}");

            // 如果已经在全局事务中，则直接执行方法
            if (!string.IsNullOrEmpty(xid))
            {
                _logger.LogDebug($"已在全局事务中，直接执行方法: XID={xid}");
                return await invocation.ProceedAsync();
            }

            // 开始新的全局事务
            var newXid = _transactionManager.Begin(attribute.TimeoutMs, attribute.Name);

            if (string.IsNullOrEmpty(newXid))
            {
                _logger.LogError($"开始全局事务失败");
                throw new TransactionException($"开始全局事务失败");
            }

            RootContext.Bind(newXid);

            try
            {
                // 执行目标方法
                var result = await invocation.ProceedAsync();

                // 提交全局事务
                await _transactionManager.CommitAsync(newXid);

                _logger.LogDebug($"全局事务已提交: XID={newXid}");
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"全局事务执行异常，开始回滚: XID={newXid}");

                // 回滚全局事务
                try
                {
                    await _transactionManager.RollbackAsync(newXid);
                    _logger.LogDebug($"全局事务已回滚: XID={newXid}");
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, $"回滚全局事务失败: XID={newXid}");
                }
                
                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
            }
        }
    }

    /// <summary>
    /// AT模式事务切面
    ///
    /// 提供基于委托的声明式事务管理，类似AtTransactionInterceptor但使用Func委托。
    ///
    /// 职责：
    /// 1. 接收业务逻辑委托（Func<Task<T>>或Func<Task>）
    /// 2. 自动开启全局事务
    /// 3. 执行委托中的业务逻辑
    /// 4. 根据执行结果自动提交或回滚全局事务
    /// 5. 管理事务上下文（绑定和解绑XID）
    ///
    /// 与AtTransactionInterceptor的区别：
    /// - AtTransactionInterceptor：基于AOP拦截器，使用[GlobalTransactional]特性
    /// - AtTransactionAspect：基于委托，手动调用ExecuteAsync()方法
    /// - 相同点：都提供声明式事务管理
    /// - 不同点：Aspect更灵活，可以在任何地方调用
    ///
    /// 工作原理：
    /// ```
    /// 1. 接收委托：Func<Task<T>> action
    /// 2. 检查当前是否已在全局事务中
    /// 3. 如果不在，开启新的全局事务
    /// 4. 绑定XID到当前上下文
    /// 5. 执行委托中的业务逻辑
    /// 6. 成功：提交全局事务
    /// 7. 失败：回滚全局事务
    /// 8. 清理上下文
    /// ```
    ///
    /// 使用场景（编程式事务）：
    /// ```csharp
    /// // 场景1：在非AOP环境中使用
    /// public class OrderService
    /// {
    ///     private readonly AtTransactionAspect _aspect;
    ///
    ///     public async Task PlaceOrderAsync(Order order)
    ///     {
    ///         var attribute = new GlobalTransactionalAttribute
    ///         {
    ///             TimeoutMs = 60000,
    ///             Name = "place-order"
    ///         };
    ///
    ///         await _aspect.ExecuteAsync(async () =>
    ///         {
    ///             // 业务逻辑
    ///             await _inventoryService.DeductAsync(order.ProductId, order.Quantity);
    ///             await _orderRepository.CreateAsync(order);
    ///             await _accountService.DeductAsync(order.UserId, order.Amount);
    ///         }, attribute);
    ///     }
    /// }
    ///
    /// // 场景2：带返回值的事务
    /// public async Task<long> CreateOrderAsync(Order order)
    /// {
    ///     return await _aspect.ExecuteAsync(async () =>
    ///     {
    ///         var orderId = await _orderRepository.CreateAsync(order);
    ///         await _inventoryService.DeductAsync(order.ProductId, order.Quantity);
    ///         return orderId;
    ///     }, new GlobalTransactionalAttribute { TimeoutMs = 30000 });
    /// }
    /// ```
    ///
    /// 与Spring TransactionTemplate的对比：
    /// - Spring TransactionTemplate：用于编程式本地事务
    /// - AtTransactionAspect：用于编程式分布式事务
    /// - 相同点：都使用委托/回调实现编程式事务
    /// - 不同点：Seata需要与TC通信，管理全局事务
    ///
    /// 适用场景：
    /// - 不支持AOP的环境（如某些IoC容器）
    /// - 动态决定是否开启事务（基于运行时条件）
    /// - 需要在同一方法中多次开启事务
    /// - 需要更细粒度的事务控制
    ///
    /// 线程安全：
    /// - 切面本身是线程安全的（注册为Transient或Scoped）
    /// - XID使用ThreadLocal/AsyncLocal存储，线程隔离
    /// - 委托内部的业务逻辑需要自行保证线程安全
    ///
    /// 注意事项：
    /// - 需要手动调用ExecuteAsync()方法
    /// - 委托内部不能包含耗时的同步操作（会阻塞线程）
    /// - RootContext.Unbind()必须在finally中执行
    /// - 异常会导致回滚，需要正确处理业务异常
    /// </summary>
    public class AtTransactionAspect
    {
        private readonly IAtTransactionManager _transactionManager;
        private readonly ILogger<AtTransactionAspect> _logger;

        /// <summary>
        /// 构造函数
        ///
        /// 初始化AT模式事务切面，注入依赖服务。
        ///
        /// 依赖服务说明：
        /// - IAtTransactionManager：AT事务管理器，用于开启、提交、回滚全局事务
        /// - ILogger：日志记录器，用于记录事务生命周期日志
        ///
        /// 注意事项：
        /// - 切面注册为Transient生命周期（每次注入创建新实例）
        /// - 或者注册为Scoped生命周期（每个请求一个实例）
        /// - 依赖的事务管理器应该是线程安全的
        /// </summary>
        /// <param name="transactionManager">AT事务管理器</param>
        /// <param name="logger">日志记录器</param>
        public AtTransactionAspect(
            IAtTransactionManager transactionManager,
            ILogger<AtTransactionAspect> logger)
        {
            _transactionManager = transactionManager;
            _logger = logger;
        }

        /// <summary>
        /// 在全局事务中执行委托（有返回值）
        ///
        /// 执行传入的委托，并自动管理全局事务的开始、提交和回滚。
        ///
        /// 执行流程：
        /// 1. 检查当前是否已在全局事务中（RootContext.GetXid()）
        /// 2. 如果已在事务中，直接执行委托（事务传播）
        /// 3. 如果不在事务中，开启新的全局事务
        /// 4. 绑定XID到当前上下文（RootContext.Bind）
        /// 5. 在try块中执行委托
        /// 6. 成功：提交全局事务，返回委托结果
        /// 7. 失败：回滚全局事务，重新抛出异常
        /// 8. finally：清理上下文（RootContext.Unbind）
        ///
        /// 调用时机：
        /// - 需要编程式事务控制时
        /// - 不支持AOP的环境中
        /// - 动态决定是否开启事务
        ///
        /// 使用示例：
        /// ```csharp
        /// // 示例1：创建订单并返回订单ID
        /// var orderId = await _aspect.ExecuteAsync(async () =>
        /// {
        ///     var order = new Order { UserId = 1001, Amount = 100 };
        ///     return await _orderRepository.CreateAsync(order);
        /// }, new GlobalTransactionalAttribute { TimeoutMs = 30000 });
        ///
        /// // 示例2：嵌套调用（事务传播）
        /// await _aspect.ExecuteAsync(async () =>
        /// {
        ///     var result1 = await ServiceA();  // 在事务中
        ///     var result2 = await _aspect.ExecuteAsync(async () =>
        ///     {
        ///         return await ServiceB();  // 传播到现有事务
        ///     }, attribute);
        ///     return result1 + result2;
        /// }, attribute);
        /// ```
        ///
        /// 注意事项：
        /// - 委托必须是异步的（Func<Task<T>>）
        /// - 委托内部抛出的异常会导致回滚
        /// - 回滚失败不影响异常的抛出
        /// - 事务传播时不开启新事务
        /// </summary>
        /// <typeparam name="T">委托返回值类型</typeparam>
        /// <param name="action">业务逻辑委托，包含需要在事务中执行的代码</param>
        /// <param name="attribute">[GlobalTransactional]特性配置（超时、名称等）</param>
        /// <returns>委托的执行结果</returns>
        /// <exception cref="TransactionException">开启事务失败时抛出</exception>
        /// <exception cref="Exception">委托内部抛出的异常会重新抛出</exception>
        public async Task<T> ExecuteAsync<T>(Func<Task<T>> action, GlobalTransactionalAttribute attribute)
        {
            var xid = RootContext.GetXid();

            _logger.LogDebug($"开始AT事务: Timeout={attribute.TimeoutMs}, Retry={attribute.Retry}");

            // 如果已经在全局事务中，则直接执行方法
            if (!string.IsNullOrEmpty(xid))
            {
                _logger.LogDebug($"已在全局事务中，直接执行方法: XID={xid}");
                return await action();
            }

            // 开始新的全局事务
            var newXid = _transactionManager.Begin(attribute.TimeoutMs, attribute.Name);

            if (string.IsNullOrEmpty(newXid))
            {
                _logger.LogError($"开始全局事务失败");
                throw new TransactionException($"开始全局事务失败");
            }

            RootContext.Bind(newXid);

            try
            {
                // 执行目标方法
                var result = await action();

                // 提交全局事务
                await _transactionManager.CommitAsync(newXid);

                _logger.LogDebug($"全局事务已提交: XID={newXid}");
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"全局事务执行异常，开始回滚: XID={newXid}");

                // 回滚全局事务
                try
                {
                    await _transactionManager.RollbackAsync(newXid);
                    _logger.LogDebug($"全局事务已回滚: XID={newXid}");
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, $"回滚全局事务失败: XID={newXid}");
                }

                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
            }
        }

        /// <summary>
        /// 在全局事务中执行委托（无返回值）
        ///
        /// 执行传入的无返回值委托，并自动管理全局事务的开始、提交和回滚。
        ///
        /// 执行流程：
        /// 1. 调用ExecuteAsync<object>()方法（有返回值版本）
        /// 2. 包装无返回值委托为返回null的委托
        /// 3. 执行包装后的委托
        /// 4. 忽略返回值（null）
        ///
        /// 调用时机：
        /// - 业务逻辑不需要返回值时
        /// - 简化调用代码（不需要指定泛型参数）
        ///
        /// 使用示例：
        /// ```csharp
        /// // 示例1：执行无返回值的业务逻辑
        /// await _aspect.ExecuteAsync(async () =>
        /// {
        ///     await _inventoryService.DeductAsync(productId, quantity);
        ///     await _orderRepository.CreateAsync(order);
        ///     await _accountService.DeductAsync(userId, amount);
        ///     // 无需返回值
        /// }, new GlobalTransactionalAttribute { TimeoutMs = 60000 });
        ///
        /// // 示例2：简化的事务调用
        /// var attribute = new GlobalTransactionalAttribute { Name = "update-inventory" };
        /// await _aspect.ExecuteAsync(async () =>
        /// {
        ///     await UpdateInventoryAsync(productId, quantity);
        /// }, attribute);
        /// ```
        ///
        /// 注意事项：
        /// - 内部委托ExecuteAsync<object>()方法
        /// - 返回值固定为null，会被忽略
        /// - 其他行为与有返回值版本完全相同
        /// - 委托内部抛出的异常会导致回滚
        /// </summary>
        /// <param name="action">业务逻辑委托（无返回值），包含需要在事务中执行的代码</param>
        /// <param name="attribute">[GlobalTransactional]特性配置（超时、名称等）</param>
        /// <exception cref="TransactionException">开启事务失败时抛出</exception>
        /// <exception cref="Exception">委托内部抛出的异常会重新抛出</exception>
        public async Task ExecuteAsync(Func<Task> action, GlobalTransactionalAttribute attribute)
        {
            await ExecuteAsync<object>(async () => 
            {
                await action();
                return null;
            }, attribute);
        }
    }

    /// <summary>
    /// AT模式事务模板
    ///
    /// 提供基于委托的编程式事务管理，类似Spring的TransactionTemplate，并向业务代码提供事务上下文。
    ///
    /// 职责：
    /// 1. 接收业务逻辑委托（Func<AtTransactionContext, Task<T>>）
    /// 2. 创建并管理AtTransactionContext事务上下文
    /// 3. 将事务上下文传递给业务逻辑（让业务代码访问事务元数据）
    /// 4. 自动开启、提交和回滚全局事务
    /// 5. 管理XID的绑定和解绑
    ///
    /// 与AtTransactionAspect的区别：
    /// - AtTransactionAspect：使用GlobalTransactionalAttribute配置事务参数
    /// - AtTransactionTemplate：使用方法参数（timeoutMs、name）配置事务
    /// - AtTransactionAspect：不向业务代码传递事务上下文
    /// - AtTransactionTemplate：向业务代码传递AtTransactionContext（可访问XID、状态等）
    ///
    /// 与Spring TransactionTemplate的对比：
    /// - Spring TransactionTemplate：用于编程式本地事务
    /// - AtTransactionTemplate：用于编程式分布式事务
    /// - 相同点：都使用模板方法模式封装事务管理逻辑
    /// - 不同点：AtTransactionTemplate传递事务上下文，方便监控和调试
    ///
    /// 工作原理：
    /// ```
    /// 1. 检查当前是否已在全局事务中
    /// 2. 如果不在，开启新的全局事务
    /// 3. 创建AtTransactionContext事务上下文
    /// 4. 绑定XID到当前线程
    /// 5. 调用委托，传入AtTransactionContext
    /// 6. 业务代码执行，可以访问context.Xid、context.Status等
    /// 7. 成功：提交全局事务
    /// 8. 失败：回滚全局事务
    /// 9. 清理上下文
    /// ```
    ///
    /// 使用场景（编程式事务 + 上下文访问）：
    /// ```csharp
    /// // 场景1：访问事务上下文
    /// public async Task<long> CreateOrderAsync(Order order)
    /// {
    ///     return await _template.ExecuteAsync(async context =>
    ///     {
    ///         // 记录事务XID到日志
    ///         _logger.LogInformation($"开始创建订单，事务XID={context.Xid}");
    ///
    ///         var orderId = await _orderRepository.CreateAsync(order);
    ///         await _inventoryService.DeductAsync(order.ProductId, order.Quantity);
    ///
    ///         // 可以访问事务开始时间
    ///         var elapsed = DateTime.UtcNow - context.BeginTime;
    ///         _logger.LogInformation($"订单创建完成，耗时{elapsed.TotalMilliseconds}ms");
    ///
    ///         return orderId;
    ///     }, timeoutMs: 60000, name: "create-order");
    /// }
    ///
    /// // 场景2：根据事务状态执行不同逻辑
    /// await _template.ExecuteAsync(async context =>
    /// {
    ///     await ExecuteBusinessLogicAsync();
    ///
    ///     // 根据事务状态发送通知
    ///     if (context.Status == TransactionStatus.Begin)
    ///     {
    ///         await SendNotificationAsync($"事务{context.Xid}已开始");
    ///     }
    /// });
    ///
    /// // 场景3：动态配置超时时间
    /// int timeout = isHighPriority ? 30000 : 60000;
    /// await _template.ExecuteAsync(async context =>
    /// {
    ///     await ProcessOrderAsync(order);
    /// }, timeoutMs: timeout);
    /// ```
    ///
    /// 适用场景：
    /// - 需要访问事务上下文（XID、状态、时间）
    /// - 需要在业务代码中记录事务信息（日志、监控）
    /// - 需要根据事务状态执行不同逻辑
    /// - 需要动态配置超时时间和事务名称
    /// - 不希望使用GlobalTransactionalAttribute特性
    ///
    /// 线程安全：
    /// - 模板本身是线程安全的（注册为Transient或Scoped）
    /// - XID使用ThreadLocal/AsyncLocal存储，线程隔离
    /// - AtTransactionContext是每次调用新创建的
    /// - 委托内部的业务逻辑需要自行保证线程安全
    ///
    /// 注意事项：
    /// - 需要手动调用ExecuteAsync()方法
    /// - 委托接收AtTransactionContext参数
    /// - timeoutMs和name作为方法参数传入（而非特性）
    /// - AtTransactionContext只读，不应该修改其状态
    /// - 异常会导致回滚，需要正确处理业务异常
    /// </summary>
    public class AtTransactionTemplate
    {
        private readonly ITransactionManager _transactionManager;
        private readonly ILogger<AtTransactionTemplate> _logger;
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 构造函数
        ///
        /// 初始化AT模式事务模板，注入依赖服务。
        ///
        /// 依赖服务说明：
        /// - ITransactionManager：通用事务管理器（而非IAtTransactionManager）
        /// - ILogger：日志记录器，用于记录事务生命周期日志
        /// - IServiceProvider：服务提供者，用于在模板中获取其他服务（可选）
        ///
        /// 注意事项：
        /// - 模板注册为Transient生命周期（每次注入创建新实例）
        /// - 或者注册为Scoped生命周期（每个请求一个实例）
        /// - 依赖的事务管理器应该是线程安全的
        /// - 使用ITransactionManager而非IAtTransactionManager，更通用
        /// </summary>
        /// <param name="transactionManager">通用事务管理器</param>
        /// <param name="logger">日志记录器</param>
        /// <param name="serviceProvider">服务提供者</param>
        public AtTransactionTemplate(
            ITransactionManager transactionManager,
            ILogger<AtTransactionTemplate> logger,
            IServiceProvider serviceProvider)
        {
            _transactionManager = transactionManager;
            _logger = logger;
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 在全局事务中执行委托（有返回值）
        ///
        /// 执行传入的委托，并向委托传递AtTransactionContext事务上下文。
        ///
        /// 执行流程：
        /// 1. 检查当前是否已在全局事务中（RootContext.GetXid()）
        /// 2. 如果已在事务中：
        ///    - 创建AtTransactionContext（xid, isNew: false）
        ///    - 直接执行委托（事务传播）
        /// 3. 如果不在事务中：
        ///    - 调用_transactionManager.BeginAsync()开启新事务
        ///    - 获取新的XID
        ///    - 如果失败，抛出TransactionException
        /// 4. 绑定XID到当前上下文（RootContext.Bind）
        /// 5. 创建新的AtTransactionContext（xid, isNew: true）
        /// 6. 在try块中执行委托：
        ///    - 调用action(context)，传入事务上下文
        ///    - 业务代码可以访问context.Xid、context.Status等
        /// 7. 如果执行成功：
        ///    - 调用_transactionManager.CommitAsync()提交全局事务
        ///    - 检查commitSuccess，如果失败抛出异常
        ///    - 返回委托执行结果
        /// 8. 如果发生异常：
        ///    - 调用_transactionManager.RollbackAsync()回滚全局事务
        ///    - 检查rollbackSuccess，记录日志
        ///    - 重新抛出原始异常
        /// 9. 在finally块中清理上下文（RootContext.Unbind）
        ///
        /// 参数说明：
        /// - timeoutMs：事务超时时间（毫秒），默认60000ms（60秒）
        /// - name：事务名称，用于日志和监控，默认null
        ///
        /// 调用时机：
        /// - 需要访问事务上下文时
        /// - 需要在业务代码中记录事务信息
        /// - 需要动态配置超时时间
        /// - 编程式事务控制
        ///
        /// 使用示例：
        /// ```csharp
        /// // 示例1：访问事务XID
        /// var orderId = await _template.ExecuteAsync(async context =>
        /// {
        ///     _logger.LogInformation($"事务XID: {context.Xid}");
        ///     return await _orderRepository.CreateAsync(order);
        /// }, timeoutMs: 30000, name: "create-order");
        ///
        /// // 示例2：监控事务耗时
        /// await _template.ExecuteAsync(async context =>
        /// {
        ///     await ExecuteBusinessLogicAsync();
        ///     var elapsed = DateTime.UtcNow - context.BeginTime;
        ///     _metricsService.RecordTransactionTime(elapsed.TotalMilliseconds);
        /// });
        ///
        /// // 示例3：嵌套事务（传播）
        /// await _template.ExecuteAsync(async context1 =>
        /// {
        ///     await ServiceA();
        ///     await _template.ExecuteAsync(async context2 =>
        ///     {
        ///         // context1.Xid == context2.Xid（传播）
        ///         // context2.IsNew == false（不是新事务）
        ///         await ServiceB();
        ///     });
        /// });
        /// ```
        ///
        /// 注意事项：
        /// - 委托接收AtTransactionContext参数
        /// - AtTransactionContext是只读的，不应该修改
        /// - timeoutMs和name作为方法参数传入
        /// - 提交和回滚操作会检查成功状态
        /// - 事务传播时不开启新事务
        /// </summary>
        /// <typeparam name="T">委托返回值类型</typeparam>
        /// <param name="action">业务逻辑委托，接收AtTransactionContext参数</param>
        /// <param name="timeoutMs">事务超时时间（毫秒），默认60000ms</param>
        /// <param name="name">事务名称，用于日志和监控，默认null</param>
        /// <returns>委托的执行结果</returns>
        /// <exception cref="TransactionException">开启或提交事务失败时抛出</exception>
        /// <exception cref="Exception">委托内部抛出的异常会重新抛出</exception>
        public async Task<T> ExecuteAsync<T>(Func<AtTransactionContext, Task<T>> action,
            int timeoutMs = 60000,
            string? name = null)
        {
            var xid = RootContext.GetXid();

            _logger.LogDebug($"开始AT事务模板: Timeout={timeoutMs}, Name={name}");

            // 如果已经在全局事务中，则直接执行方法
            if (!string.IsNullOrEmpty(xid))
            {
                _logger.LogDebug($"已在全局事务中，直接执行方法: XID={xid}");
                var context = new AtTransactionContext(xid, false);
                return await action(context);
            }

            // 开始新的全局事务
            var newXid = await _transactionManager.BeginAsync(timeoutMs, name);

            if (string.IsNullOrEmpty(newXid))
            {
                _logger.LogError($"开始全局事务失败");
                throw new TransactionException($"开始全局事务失败");
            }

            RootContext.Bind(newXid);

            try
            {
                // 创建事务上下文
                var context = new AtTransactionContext(newXid, true);

                // 执行目标方法
                var result = await action(context);

                // 提交全局事务
                var commitSuccess = await _transactionManager.CommitAsync(newXid);

                if (!commitSuccess)
                {
                    _logger.LogError($"提交全局事务失败: XID={newXid}");
                    throw new TransactionException($"提交全局事务失败");
                }

                _logger.LogDebug($"全局事务已提交: XID={newXid}");
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"全局事务执行异常，开始回滚: XID={newXid}");

                // 回滚全局事务
                var rollbackSuccess = await _transactionManager.RollbackAsync(newXid);

                if (!rollbackSuccess)
                {
                    _logger.LogError($"回滚全局事务失败: XID={newXid}");
                }
                else
                {
                    _logger.LogDebug($"全局事务已回滚: XID={newXid}");
                }

                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
            }
        }

        /// <summary>
        /// 在全局事务中执行委托（无返回值）
        ///
        /// 执行传入的无返回值委托，并向委托传递AtTransactionContext事务上下文。
        ///
        /// 执行流程：
        /// 1. 调用ExecuteAsync<object>()方法（有返回值版本）
        /// 2. 包装无返回值委托为返回null的委托
        /// 3. 将AtTransactionContext传递给委托
        /// 4. 执行包装后的委托
        /// 5. 忽略返回值（null）
        ///
        /// 调用时机：
        /// - 业务逻辑不需要返回值时
        /// - 需要访问事务上下文
        /// - 简化调用代码（不需要指定泛型参数）
        ///
        /// 使用示例：
        /// ```csharp
        /// // 示例1：执行无返回值的业务逻辑并访问上下文
        /// await _template.ExecuteAsync(async context =>
        /// {
        ///     _logger.LogInformation($"事务XID: {context.Xid}");
        ///     await _inventoryService.DeductAsync(productId, quantity);
        ///     await _orderRepository.CreateAsync(order);
        ///     await _accountService.DeductAsync(userId, amount);
        /// }, timeoutMs: 60000, name: "place-order");
        ///
        /// // 示例2：监控事务执行时间
        /// await _template.ExecuteAsync(async context =>
        /// {
        ///     await ExecuteBusinessLogicAsync();
        ///     var elapsed = DateTime.UtcNow - context.BeginTime;
        ///     _metricsService.RecordTime("transaction.time", elapsed.TotalMilliseconds);
        /// });
        ///
        /// // 示例3：根据事务状态记录日志
        /// await _template.ExecuteAsync(async context =>
        /// {
        ///     await UpdateInventoryAsync(product);
        ///     _logger.LogInformation($"库存更新完成，XID={context.Xid}, 状态={context.Status}");
        /// }, timeoutMs: 30000);
        /// ```
        ///
        /// 注意事项：
        /// - 内部委托ExecuteAsync<object>()方法
        /// - 返回值固定为null，会被忽略
        /// - 委托接收AtTransactionContext参数
        /// - 其他行为与有返回值版本完全相同
        /// - 委托内部抛出的异常会导致回滚
        /// </summary>
        /// <param name="action">业务逻辑委托（无返回值），接收AtTransactionContext参数</param>
        /// <param name="timeoutMs">事务超时时间（毫秒），默认60000ms</param>
        /// <param name="name">事务名称，用于日志和监控，默认null</param>
        /// <exception cref="TransactionException">开启或提交事务失败时抛出</exception>
        /// <exception cref="Exception">委托内部抛出的异常会重新抛出</exception>
        public async Task ExecuteAsync(Func<AtTransactionContext, Task> action,
            int timeoutMs = 60000,
            string? name = null)
        {
            await ExecuteAsync<object>(async context => 
            {
                await action(context);
                return null;
            }, timeoutMs, name);
        }
    }
}